#include "ssd2828.h"

#include "ST7703__BV055HDE_N47_3Q00.h"

void Delay_spi(void)
{
    volatile uint32_t i, j;

    i = 0xff;
    while (i--)
    {
        j++;
        __NOP();
    }
}

void spi_init(void)
{
    SET_CS();
    CLR_SDA();
    CLR_CLK();
}

void spi_bit(uint8_t sda)
{
    if (sda != 0)
    {
        SET_SDA();
    }
    else
    {
        CLR_SDA();
    }
    Delay_spi();

    SET_CLK();
    Delay_spi();

    CLR_CLK();
}

void spi_byte(uint8_t data)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        spi_bit((data << i) & 0x80);
    }
}

uint8_t spi_read(void)
{
    uint8_t rdT = 0x00;
    for (uint8_t kk = 0; kk < 8; kk++)
    {
        rdT = rdT << 1;
        SET_CLK();
        Delay_spi();

        if (getMISO())
        {
            rdT |= 0x01;
        }
        CLR_CLK();
        Delay_spi();
    }

    return rdT;
}

/*void spi_write(uint8_t cod, uint8_t data)
{
    CLR_CS();
    spi_bit(cod);
    spi_byte(data);
    SET_CS();
}*/

void ssd2828_writeReg(uint8_t addr, uint8_t data15_8, uint8_t data7_0)
{
    CLR_CS();

    spi_bit(0);
    spi_byte(addr);

    spi_bit(1);
    spi_byte(data7_0);

    spi_bit(1);
    spi_byte(data15_8);

    SET_CS();
}

uint16_t ssd2828_readReg(uint8_t reg)
{
    uint8_t rdT;
    uint16_t reValue;

    CLR_CS();
    Delay_spi();

    spi_bit(0);
    spi_byte(reg);

    spi_bit(0);
    spi_byte(0xfa);

    rdT = spi_read();

    reValue = rdT;

    rdT = spi_read();

    reValue += (rdT << 8);

    SET_CS();
    Delay_spi();

    return reValue;
}

//void spi_writeMulti()

void ssd2828_dsiWriteMulti_A(uint8_t format, uint16_t len, uint8_t *array)
{
    sendFormat(format, len);

    for (uint16_t i = 0; i < len; i++)
    {
        W_D(array[i]);
    }
}

void ssd2828_dsiWriteMulti_B(uint8_t format, uint8_t *array)
{
    sendFormat(format, array[0]);

    for (uint16_t i = 1; i < array[0]; i++)
    {
        W_D(array[i]);
    }
}

void Write_Byte(u8 num)
{
    u8 count;
    for (count = 0; count < 8; count++)
    {
        if (num & 0x80)
            SET_SDA();
        else
            CLR_SDA();
        Delay_spi();

        SET_CLK();

        num <<= 1;
        Delay_spi();

        CLR_CLK();
        //Delay_spi();
    }
}

void W_C(u8 CMD)
{
    CLR_CLK();
    CLR_CS();
    Delay_spi();

    CLR_SDA();
    Delay_spi(); //BIT8(D/C)=0 REG

    SET_CLK();
    Delay_spi();

    CLR_CLK();
    Delay_spi();

    Write_Byte(CMD);

    SET_CS();
    Delay_spi();
}

void W_D(u8 DAT)
{
    CLR_CLK();
    CLR_CS();
    Delay_spi();

    SET_SDA();
    Delay_spi(); //BIT8(D/C)=0 REG

    SET_CLK();
    Delay_spi();

    CLR_CLK();
    Delay_spi();

    Write_Byte(DAT);

    SET_CS();
    Delay_spi();
}

void GP_COMMAD_PA(u16 a)
{
    W_C(0xBC);
    W_D(a);
    W_D(a >> 8);
    W_C(0xBF);
}

void sendFormat(u8 format, u16 len)
{
    //LCD driver initialization
    W_C(0xB7);
    if (format)
    {              //DCS
        W_D(0x50); //10=TX_CLK 30=PCLK
    }
    else
    {              //GEN
        W_D(0x10); //10=TX_CLK 30=PCLK
    }
    W_D(0x02);

    W_C(0xBD);
    W_D(0x00);
    W_D(0x00);

    W_C(0xBC);
    W_D(len);
    W_D(len >> 8);
    W_C(0xBF);
}

void testSendFormat(void)
{
    /*while(1){
    
    //13 gen 1p
    //sendFormat(GEN, 1); 
    //W_D(0xB1);
    
    //23 gen 2p
    //sendFormat(GEN, 2); 
    //W_D(0xB0);W_D(0x04);
       
    //29 gen long
    //sendFormat(GEN, 3); 
    //W_D(0xB1);W_D(0xB1);W_D(0xB1);
    
    
    
    //05 dcs 0p
    //sendFormat(DCS, 1); 
    //W_D(0x11);
    
    //15 dcs 1p
    //sendFormat(DCS, 2); 
    //W_D(0x11);W_D(0x29);
        
    //39 dcs long
    sendFormat(DCS, 3); 
    W_D(0x11);W_D(0x29);W_D(0x10);
  }*/
}

U16 SPI_READ_REG(U8 reg)
{
    U8 /*cmd, */ rdT;
    U16 reValue;
    //U32 kk;

    CLR_CS();
    Delay_spi();
    /*
    CLR_SDA(); //Set DC=0, for writing to Command register
    Delay_spi();
    CLR_CLK();
    Delay_spi();
    SET_CLK();
    Delay_spi();
    */

    spi_bit(0);

    /*cmd = reg;
    CLR_CLK();
    Delay_spi();
    for (kk = 0; kk < 8; kk++)
    {
        if ((cmd & 0x80) == 0x80)
        {
            SET_SDA();
            Delay_spi();
        }
        else
        {
            CLR_SDA();
            Delay_spi();
        }
        SET_CLK();
        Delay_spi();
        CLR_CLK();
        Delay_spi();
        cmd = cmd << 1;
    }*/
    spi_byte(reg);

    /*CLR_SDA();
    Delay_spi(); //Set DC=0, for writing to Command register
    CLR_CLK();
    Delay_spi();
    SET_CLK();
    Delay_spi();*/
    spi_bit(0);

    /*cmd = 0xFA;
    CLR_CLK();
    Delay_spi();
    for (kk = 0; kk < 8; kk++)
    {
        if ((cmd & 0x80) == 0x80)
        {
            SET_SDA();
            Delay_spi();
        }
        else
        {
            CLR_SDA();
            Delay_spi();
        }
        SET_CLK();
        Delay_spi();
        CLR_CLK();
        Delay_spi();
        cmd = cmd << 1;
    }*/
    spi_byte(0xfa);

    /*rdT = 0;
    for (kk = 0; kk < 8; kk++)
    {
        rdT = rdT << 1;
        SET_CLK();
        Delay_spi();
        
        
        if (getMISO())
        {
            rdT |= 0x01;
        }
        CLR_CLK();
        Delay_spi();
    }*/
    rdT = spi_read();

    reValue = rdT;
    //reValue = (reValue<<8)&0xFF00;

    /*rdT = 0;
    for (kk = 0; kk < 8; kk++)
    {
        rdT = rdT << 1;
        SET_CLK();
        Delay_spi();


        if (getMISO())
        {
            rdT |= 0x01;
        }
        CLR_CLK();
        Delay_spi();
    }
*/
    rdT = spi_read();

    reValue += (rdT << 8);

    SET_CS();
    Delay_spi();

    return reValue;
}

void Wr_com_data16(U8 c, U16 value)
{
    CLR_CS();
    W_C(c);
    W_D(value & 0xff);
    W_D((value >> 8) & 0xff);
    SET_CS();
}

void ssd2828_readID(void)
{
    printf("ssd2828_readID\r\n");
    int a;
    Wr_com_data16(0xd4, 0x00FA);
    a = SPI_READ_REG(0xb0);
    if (a == 0x2828)
    {
        printf(" \r\n");
        printf("The SSD2828 ID: 0x%x  ^-^  successful !! \r\n", a);
        printf(" \r\n");
    }
    else
    {
        printf(" \r\n");
        printf("The SSD2828 ID: 0x%x  -_-! failing !!!! \r\n", a);
        printf(" \r\n");
    }
}

void readMipi(U8 type, U8 lpclk, U8 returnLen, U8 mipiSlaveRegAddr, U16 *returnData)
{
    U16 data0xC6, i;
    U8 /*cmd, */ rdT;
    U16 reValue;
    U32 kk;

    do
    {
        //---------------------SETP1---------------------
        // Send 0xB7 0x82, 0x03 e.g. LP generic read
        //W_C(0xb7); W_D(0x82); W_D(0x03); //generic read
        W_C(0xb7);

        switch (type)
        {
        case DCS:
            W_D(0xC2);
            break;

        case GEN:
            W_D(0x82);
            break;

        default:
            break;
        }
        W_D(0x03); // DCS read

        // Send 0xBB 0xXX, 0x00 "XX" is the register for LP freq. setting Rx internal clock freq. must be similar to Tx
        W_C(0xBB);
        W_D(lpclk);
        W_D(0x00);
        // Send 0xC1 0x0A, 0x00 Max. return packet is 255 bytes
        W_C(0xC1);
        W_D(returnLen);
        W_D(0x00);
        // Send 0xC0 0x00, 0x01
        W_C(0xC0);
        W_D(0x00);
        W_D(0x01);
        // Send 0xBC 0x01, 0x00
        W_C(0xBC);
        W_D(0x01);
        W_D(0x00);
        // Send 0xBF 0xXX, 0x00 "XX" is the register of display driver
        W_C(0xBF);
        W_D(mipiSlaveRegAddr);
        W_D(0x00);

        //MIPI Read

        // check 0xC6 bit 0, aka RDR register, Read Data Ready
        // Preparation for 0xFF read
        // Send 0xD4 0xFA, 0x00 Set read command "FA" for 3 wire 8bit
        W_C(0xD4);
        W_D(0xFA);
        W_D(0x00);
        // Send C6h, with DC bit =0 Read register 0xC6
        // Send 0xFA, with DC bit =0 "FA" read command
        // Read data from SDO Data [7:0] Confirm bit0 is "1
        // Read data from SDO Data [15:8]
        //data0xC6 = SPI_READ_REG(0xC6);
        data0xC6 = SPI_READ_REG(0xb0);
        printf("0xC6 = 0x%x\r\n", data0xC6);
        //UART1_Printf("0xC6\r\n");
        //UART1_SendData8(0xC6);
        HAL_Delay(1);
    } while ((data0xC6 & 0x0001) == 0);

    //---------------------SETP2---------------------
    // loop to read data
    // Send FFh, with DC bit =0
    W_C(0xFF);
    for (i = 0; i < returnLen; i++)
    {
        // Send 0xFA, with DC bit =0
        W_C(0xFA);

        //CLR_CLK();
        CLR_CLK();
        Delay_spi();
        //LCD_CS_CLR;
        CLR_CS();
        Delay_spi();
        // Read data from SDO Data [7:0]
        rdT = 0;
        for (kk = 0; kk < 8; kk++)
        {
            rdT = rdT << 1;
            //SET_CLK();
            SET_CLK();
            Delay_spi();
            //if(GPIO_ReadInputPin(/*PD3*/ GPIOD, GPIO_PIN_3)){
            if (getMISO())
            {
                rdT |= 0x01;
            }
            CLR_CLK();
            Delay_spi();
        }
        reValue = rdT;

        // Read data from SDO Data [15:8]
        rdT = 0;
        for (kk = 0; kk < 8; kk++)
        {
            rdT = rdT << 1;
            //SET_CLK();
            SET_CLK();
            Delay_spi();
            //if(GPIO_ReadInputPin(/*PD3*/ GPIOD, GPIO_PIN_3)){
            if (getMISO())
            {
                rdT |= 0x01;
            }
            CLR_CLK();
            Delay_spi();
        }

        reValue += (rdT << 8);

        returnData[i] = reValue;
        //SET_CS();
        SET_CS();
        Delay_spi();
    }
}

void ssd2828_hwreset(void)
{
    SET_RST();
    delay_ms(100); //(Min 10mS)

    CLR_RST();     //Reset Signal generate
    delay_ms(100); //(Min 10mS)

    SET_RST();
    delay_ms(100);
}

void Init_SSD2828(void (*lcd_init)(void))
{

    /*SET_RST();
    //delay_ms(100);
    delay_ms(100); //(Min 10mS)
    CLR_RST();     //Reset Signal generate
    delay_ms(100); //(Min 10mS)
    //delay_ms(1000);
    //delay_ms(1000);
    SET_RST();
    delay_ms(100);*/

    //ssd2828_readID();

    //while(1);

    /*============================================================================*/

    //SSD2828_Initial
    W_C(0xb7);
    W_D(0x50); //50=TX_CLK 70=PCLK
    W_D(0x00); //Configuration Register

    W_C(0xb8);
    W_D(0x00);
    W_D(0x00); //VC(Virtual ChannelID) Control Register

    W_C(0xb9);
    W_D(0x00); //1=PLL disable
    W_D(0x00);
    //TX_CLK/MS should be between 5Mhz to100Mhz
    W_C(0xBA); //PLL=(TX_CLK/MS)*NS 8228=480M 4428=240M  061E=120M 4214=240M 821E=360M 8219=300M
    W_D(0x24); //D7-0=NS(0x01 : NS=1)
    W_D(0x82); //D15-14=PLL范围 00=62.5-125 01=126-250 10=251-500 11=501-1000  DB12-8=MS(01:MS=1)

    W_C(0xBB); //LP Clock Divider LP clock = 400MHz / LPD / 8 = 240 / 8 / 4 = 7.5MHz
    W_D(0x03); //D5-0=LPD=0x1 – Divide by 2
    W_D(0x00);

    W_C(0xb9);
    W_D(0x01); //1=PLL disable
    W_D(0x00);
    //MIPI lane configuration
    W_C(0xDE); //通道数
    W_D(0x03); //11=4LANE 10=3LANE 01=2LANE 00=1LANE
    W_D(0x00);

    W_C(0xc9);
    W_D(0x02);
    W_D(0x23); //p1: HS-Data-zero  p2: HS-Data- prepare  --> 8031 issue
    delay_ms(100);

    /*============================================================================*/

    //LCD driver initialization
    W_C(0xB7);
    W_D(0x10); //10=TX_CLK 30=PCLK
    W_D(0x02);

    W_C(0xBD);
    W_D(0x00);
    W_D(0x00);

    /*======LCD INITIAL===========================================================*/

    delay_ms(100);

    lcd_init();

    delay_ms(200);
    /*============================================================================*/
    // 11 29 old
    GP_COMMAD_PA(0x01);
    W_D(0x11);
    delay_ms(100);

    GP_COMMAD_PA(0x01);
    W_D(0x29);
    delay_ms(100);

    ;

    W_C(0xBC);
    W_D(0x00);
    W_D(0x00);

    //W_C(0xBF);
    W_C(0x11); //
    //W_D(0x00);     //
    delay_ms(100);

    W_C(0xBC);
    W_D(0x00);
    W_D(0x00);
    //W_C(0xBF);
    W_C(0x29); //  Display On
    delay_ms(200);

    /*==============================================================================================================================*/

    W_C(0xb7);
    W_D(0x50);
    W_D(0x00); //Configuration Register

    W_C(0xb8);
    W_D(0x00);
    W_D(0x00); //VC(Virtual ChannelID) Control Register

    W_C(0xb9);
    W_D(0x00); //1=PLL disable
    W_D(0x00);

    W_C(0xBA); //PLL=(TX_CLK/MS)*NS 8228=480M 4428=240M  061E=120M 4214=240M 821E=360M 8219=300M 8225=444M 8224=432
    W_D(0x28); //D7-0=NS(0x01 : NS=1)
    W_D(0x82); //D15-14=PLL范围 00=62.5-125 01=126-250 10=251-500 11=501-1000  DB12-8=MS(01:MS=1)

    W_C(0xBB); //LP Clock Divider LP clock = 400MHz / LPD / 8 = 480 / 8/ 8 = 7MHz
    W_D(0x07); //D5-0=LPD=0x1 – Divide by 2
    W_D(0x00);

    W_C(0xb9);
    W_D(0x01); //1=PLL disable
    W_D(0x00);

    W_C(0xc9);
    W_D(0x02);
    W_D(0x23); //p1: HS-Data-zero  p2: HS-Data- prepare  --> 8031 issue
    delay_ms(10);

    W_C(0xCA);
    W_D(0x01); //CLK Prepare
    W_D(0x23); //Clk Zero

    W_C(0xCB); //local_write_reg(addr=0xCB,data=0x0510)
    W_D(0x10); //Clk Post
    W_D(0x05); //Clk Per

    W_C(0xCC); //local_write_reg(addr=0xCC,data=0x100A)
    W_D(0x05); //HS Trail
    W_D(0x10); //Clk Trail

    W_C(0xD0);
    W_D(0x00);
    W_D(0x00);

    //RGB interface configuration
    W_C(0xB1);
    W_D(HSPW); //HSPW 07
    W_D(VSPW); //VSPW 05

    W_C(0xB2);
    W_D(HBPD); //HBPD 0x64=100
    W_D(VBPD); //VBPD 8 减小下移

    W_C(0xB3);
    W_D(HFPD); //HFPD 8
    W_D(VFPD); //VFPD 10

    W_C(0xB4); //Horizontal active period 720=02D0
    W_D(0xD0); //013F=319 02D0=720
    W_D(0x02);

    W_C(0xB5); //Vertical active period 1280=0500
    W_D(0x00); //01DF=479 0500=1280
    W_D(0x05);

    W_C(0xB6); //RGB CLK  16BPP=00 18BPP=01
    W_D(0x07); //D7=0 D6=0 D5=0  D1-0=11 – 24bpp
    W_D(0x20); //D15=VS D14=HS D13=CLK D12-9=NC D8=0=Video with blanking packet. 00-F0

    //MIPI lane configuration
    W_C(0xDE); //通道数
    W_D(0x03); //11=4LANE 10=3LANE 01=2LANE 00=1LANE
    W_D(0x00);

    W_C(0xD6); //  05=BGR  04=RGB
    W_D(0x05); //D0=0=RGB 1:BGR D1=1=Most significant byte sent first
    W_D(0x00);

    W_C(0xB7);
    W_D(0x4B);
    W_D(0x02);

    //W_C(0x2C);
    //W_C(0x3C);
}